package com.example.lucky.draw.server.aspect;

import com.example.lucky.draw.server.common.annotation.OperationLog;
import com.example.lucky.draw.server.protocol.po.UserLog;
import com.example.lucky.draw.server.service.IUserLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
public class LogAspect {

    @Autowired
    private IUserLogService userLogService;

    @Pointcut("@annotation(com.example.lucky.draw.server.common.annotation.OperationLog)")
    public void doLog(){}

    @Around("doLog()")
    public Object doLogAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //初始状态
        int status=1;
        //错误信息
        String error=null;
        //耗时
        long time=0l;

        //开始执行日志处理
        long t1 = System.currentTimeMillis();
        try{
            //调用目标业务执行链（可能会又其他切面的扩展业务）
            Object result = joinPoint.proceed();
            long t2 = System.currentTimeMillis();
            time=t2-t1;
            return result;
        } catch (Throwable e) {
            long t3 = System.currentTimeMillis();
            time=t3-t1;
            status=0;//表示失败状态
            error=e.getMessage();
            throw e;
        }finally {
            saveOperationLog(joinPoint,time,status,error);
        }
    }

    private void saveOperationLog(ProceedingJoinPoint joinPoint, long time, int status, String error) throws NoSuchMethodException, JsonProcessingException {
        //获取用户行为日志
        //RequestContextHolder是一个工具类，用于在当前环境中获取当前处理的HTTP请求和响应上下文对象
        ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest httpServletRequest = requestAttributes.getRequest();
        //获取IP地址
        String ip=httpServletRequest.getRemoteAddr();
        //获取用户名
        String username="tedu";
        //获取类的字节码文件
        Class<?> targetCls = joinPoint.getTarget().getClass();
        //获取方法声明
        MethodSignature ms = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
        //获取方法上所添加的注解
        OperationLog annotation = targetMethod.getAnnotation(OperationLog.class);
        //获取方法操作描述
        String operation = annotation.operation();
        //获取的方法名称
        String method=targetCls.getName()+"."+targetMethod.getName();
        //获取方法参数
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        String params = objectMapper.writeValueAsString(joinPoint.getArgs());
        //封装用户日志对象
        UserLog userLog = new UserLog(
                null,username,ip,operation,method,params,time, LocalDateTime.now(),status,error
        );
        userLogService.save(userLog);
    }
}
